/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_kernel.htm
 *
 * Zhiqim Kernel is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.kernel.config;

import java.io.Serializable;
import java.util.Collection;
import java.util.Map;

import org.zhiqim.kernel.constants.SignConstants;
import org.zhiqim.kernel.constants.ZhiqimConstants;
import org.zhiqim.kernel.model.maps.LinkedMapSV;
import org.zhiqim.kernel.util.Strings;

/**
 * 工程配置组，每个工程配置类有多个配置组<br><br>
 * 每个配置组，有id,desc两个属性<br>
 * 每个配置组，有多个Item(工程配置项)
 * 
 * 1.XML配置格式
 * <group id="boot" type="private" desc="系统启动配置">
 *     <item key="name" value="Zhiqim Server" type="protected" desc="系统名称" />
 *     <item key="version" value="1.0.1.1" type="protected" desc="系统版本" />
 *     <item key="port" value="60067" type="protected" desc="系统监听端口，用于启动监听和命令关闭工程" />
 * </group>
 *  
 * 2.INI配置格式
 * #系统启动配置
 * [boot]
 * #系统名称
 * name=Zhiqim Server
 * #public系统版本
 * version=1.0.1.1
 * #private系统监听端口，用于启动监听和命令关闭工程
 * port=60067
 *    
 * @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
 */
public class Group implements Serializable, ZhiqimConstants, SignConstants
{
    private static final long serialVersionUID = 1L;
    
    //父配置类
    private Config config;
    
    //配置组两个参数
    private String id;
    private ItemType type;
    private String desc;
    private char symbol;
    
    //配置项表
    private LinkedMapSV<Item> itemMap = new LinkedMapSV<Item>();
    
    /********************************************************************/
    //构造函数
    /********************************************************************/
    
    public Group(String id)
    {
        this(null, id, null);
    }
    
    public Group(Config config, String id, String desc)
    {
        this(config, id, ItemType.PROTECTED, desc, '#');
    }
    
    public Group(Config config, String id, ItemType type, String desc)
    {
        this(config, id, type, desc, '#');
    }
    
    public Group(Config config, String id, String desc, char symbol)
    {
        this(config, id, ItemType.PROTECTED, desc, symbol);
    }
    
    public Group(Config config, String id, ItemType type, String desc, char symbol)
    {
        this.config = config;
        this.id = id;
        this.type = type;
        this.desc = desc;
        this.symbol = symbol;
    }

    public String ignoreCase(String value)
    {
        return (config != null && config.isIgnoreCase())?value.toLowerCase():value;
    }
    
    public Group clone()
    {
        Group newGroup = new Group(config, id, type, desc, symbol);
        
        for (Map.Entry<String, Item> entry : itemMap.entrySet())
        {
            newGroup.add(entry.getValue().clone().setGroup(newGroup));
        }
        
        return newGroup;
    }
    
    /********************************************************************/
    //以下为Group运行时生成字符串和支持增加配置项
    /********************************************************************/
    
    public String toString()
    {
        if (isXml())
        {
            StringBuilder strb = new StringBuilder(_FOUR_).append("<group")
                .append(" id=").append(_DOUBLE_QUOTE_).append(id).append(_DOUBLE_QUOTE_);
            
            if (!isProtected())
                strb.append(" type=").append(_DOUBLE_QUOTE_).append(ItemType.toString(type)).append(_DOUBLE_QUOTE_);
            
           strb.append(" desc=").append(_DOUBLE_QUOTE_).append(desc).append(_DOUBLE_QUOTE_)
                .append(">")
                .append(_BR_);
            
            for (Item item : itemMap.values())
            {
                strb.append(_FOUR_).append(_FOUR_).append(item).append(_BR_);
            }
            
            strb.append(_FOUR_).append("</group>");
            return strb.toString();
        }
        else
        {
            StringBuilder strb = new StringBuilder();
            if (desc != null)
                strb.append(symbol).append(desc).append(_BR_);
            strb.append("[").append(id).append("]").append(_BR_);
            
            for (Item item : itemMap.values())
            {
                strb.append(item).append(_BR_);
            }
            
            return strb.toString();
        }
    }
    
    /** 重置组号 */
    public Group setId(String id)
    {
        this.id = id;
        return this;
    }
    
    /********************************************************************/
    //以下为Group操作方法
    /********************************************************************/
    
    /**
     * 添加一个配置项，简单的只有KEY和VALUE
     * 
     * @param key       配置键
     * @param value     配置值
     * @return =true表示添加成功,=false表示有重复的配置键
     */
    public boolean add(String key, String value)
    {
        return add(new Item(this, key, value, ItemType.PROTECTED, null));
    }
    
    /**
     * 添加一个配置项，简单的只有KEY和VALUE
     * 
     * @param key       配置键
     * @param value     配置值
     * @return =true表示添加成功,=false表示有重复的配置键
     */
    public boolean add(String key, Object value)
    {
        return add(key, Strings.valueOf(value));
    }
    
    /**
     * 添加一个配置项
     * 
     * @param key       配置键
     * @param value     配置值
     * @param type      配置类型private|protected|public，分别表示私有不可见，可见，可见且支持修改
     * @param desc      配置描述
     * @return =true表示添加成功,=false表示有重复的配置键
     */
    public boolean add(String key, String value, ItemType type, String desc)
    {
        return add(new Item(this, key, value, type, desc));
    }
    
    /**
     * 添加一个配置项
     * 
     * @param key       配置键
     * @param value     配置值
     * @param type      配置类型private|protected|public，分别表示私有不可见，可见，可见且支持修改
     * @param desc      配置描述
     * @return =true表示添加成功,=false表示有重复的配置键
     */
    public boolean add(String key, String value, ItemType type, String desc, char symbol)
    {
        return add(new Item(this, key, value, type, desc, symbol));
    }
    
    /**
     * 添加一个配置项
     * 
     * @param key       配置键
     * @param value     配置值
     * @param update    业务是否实时修改
     * @param desc      配置描述
     * @return =true表示添加成功,=false表示有重复的配置键
     */
    public boolean add(Item item)
    {
        String keyCase = ignoreCase(item.getKey());
        if (itemMap.containsKey(keyCase))
            return false;
        
        this.itemMap.put(keyCase, item);
        return true;
    }
    
    /**
     * 删除一个配置项
     *
     * @param key   配置键
     * @return =true表示删除成功,=false表示无配置项
     */
    public boolean remove(String key)
    {
        return itemMap.remove(ignoreCase(key)) != null;
    }
    
    /********************************************************************/
    //以下为Group属性
    /********************************************************************/
    
    public String getId()
    {
        return id;
    }

    public String getDesc()
    {
        return desc;
    }
    

    public ItemType getType()
    {
        return type;
    }
    
    public String getTypeString()
    {
        return ItemType.toString(type);
    }
    
    public boolean isPublic()
    {
        return ItemType.PUBLIC == type;
    }
    
    public boolean isProtected()
    {
        return ItemType.PROTECTED == type;
    }
    
    public boolean isPrivate()
    {
        return ItemType.PRIVATE == type;
    }

    public boolean isEmpty()
    {
        return itemMap.isEmpty();
    }
    
    public int size()
    {
        return itemMap.size();
    }
    
    public Collection<Item> list()
    {
        return itemMap.values();
    }
    
    public LinkedMapSV<Item> map()
    {
        return itemMap;
    }
    
    public boolean hasItem(String key)
    {
        return itemMap.containsKey(ignoreCase(key));
    }
    
    public Item item(String key)
    {
        return itemMap.get(ignoreCase(key));
    }
    
    public String getString(String key)
    {
        Item item = item(key);
        return (item == null)?null:item.getString();
    }
    
    public String getString(String key, String defaultValue)
    {
        Item item = item(key);
        return (item == null)?defaultValue:item.getString(defaultValue);
    }
    
    public int getInt(String key)
    {
        Item item = item(key);
        return (item == null)?-1:item.getInt();
    }
    
    public int getInt(String key, int defaultValue)
    {
        Item item = item(key);
        return (item == null)?defaultValue:item.getInt(defaultValue);
    }
    
    public long getLong(String key)
    {
        Item item = item(key);
        return (item == null)?-1:item.getLong();
    }
    
    public long getLong(String key, long defaultValue)
    {
        Item item = item(key);
        return (item == null)?defaultValue:item.getLong(defaultValue);
    }
    
    public boolean isTrue(String key)
    {
        Item item = item(key);
        return (item == null)?false:item.isTrue();
    }
    
    public boolean isTrue(String key, boolean defaultValue)
    {
        Item item = item(key);
        return (item == null)?defaultValue:item.isTrue();
    }
    
    /********************************************************************/
    //下面是Config的属性
    /********************************************************************/
    
    public String getName()
    {
        return config == null?null:config.getName();
    }
    
    public String getPath()
    {
        return config == null?null:config.getPath();
    }
    
    public boolean isXml()
    {
        return config != null && config.isXml();
    }
    
    public boolean isIni()
    {
        return config == null || config.isIni();
    }
    
    public boolean isIgnoreCase()
    {
        return config != null && config.isIgnoreCase();
    }

    /********************************************************************/
    //以下定义Group相等，当id相等即相等
    /********************************************************************/
    
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Group other = (Group) obj;
        if (id == null)
        {
            if (other.id != null)
                return false;
        }
        else if (!id.equals(other.id))
            return false;
        return true;
    }
}
